home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 30 / Mac Magazin and MacEasy Magazine CD - Issue 30.iso / utilities / Mac OS X / Load_Monitor / src / MainController.m < prev    next >
Encoding:
Text File  |  2002-01-14  |  16.5 KB  |  437 lines

  1. /*
  2.  *    Load Monitor
  3.  *
  4.  *    Copyright © 2001 Alexandre Vial, some parts from Bernhard Baehr
  5.  *
  6.  *    MainController.m - Main Application Controller Class
  7.  *
  8.  *    This program is free software; you can redistribute it and/or modify
  9.  *    it under the terms of the GNU General Public License as published by
  10.  *    the Free Software Foundation; either version 2 of the License, or
  11.  *    (at your option) any later version.
  12.  *
  13.  *    This program is distributed in the hope that it will be useful,
  14.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *    GNU General Public License for more details.
  17.  *
  18.  *    You should have received a copy of the GNU General Public License
  19.  *    along with this program; if not, write to the Free Software
  20.  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21.  */
  22.  
  23.  
  24. #import "MainController.h"
  25.  
  26. #import "AboutBox.h"
  27. #import <Carbon/Carbon.h>
  28.  
  29. #define GRAPH_SIZE    128
  30.  
  31.  
  32. @implementation MainController
  33.  
  34. - (void)drawImageOnWindow
  35. {
  36.     [iconImage drawInRect:NSMakeRect(0, 0, NSWidth([window frame]), NSHeight([window frame]))
  37.         fromRect:NSMakeRect(0, 0, GRAPH_SIZE, GRAPH_SIZE) operation:NSCompositeCopy
  38.         fraction:1.0];
  39. }
  40.  
  41.  
  42. - (void)showHideWindow
  43. {
  44.     float    size;
  45.     
  46.     if ([[preferences objectForKey:SHOW_GRAPH_WINDOW_KEY] boolValue]) {
  47.         size = [[preferences objectForKey:GRAPH_WINDOW_SIZE_KEY] floatValue];
  48.         [window setContentSize:NSMakeSize(size, size)];
  49.         [window orderWindow:NSWindowBelow relativeTo:[preferences windowNumber]];
  50.         [window setLevel:([[preferences objectForKey:GRAPH_WINDOW_ON_TOP_KEY] boolValue] ?
  51.             NSFloatingWindowLevel : NSNormalWindowLevel)];
  52.     } else
  53.         [window orderOut:self];
  54. }
  55.  
  56.  
  57. - (void)drawPageins:(double)load1 pageouts:(double)load2 load0:(double)load0
  58. {
  59.     NSString        *string;
  60.     NSMutableDictionary    *fontAttrs;
  61.         int y;
  62.         NSString        *aString;
  63.         NSSize            aSize;
  64.         
  65.         int            delta_coeff; // if load > 9, only display 2,4,6,... feature introduced for Leon
  66.         
  67.         BOOL showGauge = [[preferences objectForKey:PAGEIN_ATOP_PAGEOUT_KEY] boolValue];
  68.                                     
  69.     // draw paging rate into the icon image
  70.     if ([[preferences objectForKey:SHOW_PAGING_RATE_KEY] boolValue]) {
  71.             
  72.                 string = [NSString stringWithFormat:@"Load: "];            
  73.             
  74.             fontAttrs = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  75.                 [NSFont boldSystemFontOfSize:16.0], NSFontAttributeName,
  76.                 [NSColor blackColor], NSForegroundColorAttributeName,
  77.                 nil];
  78.             [string drawAtPoint:NSMakePoint(4.0, 106.0) withAttributes:fontAttrs];
  79.             [fontAttrs setObject:[NSColor whiteColor] forKey:NSForegroundColorAttributeName];
  80.             [string drawAtPoint:NSMakePoint(2.0, 108.0) withAttributes:fontAttrs];
  81.  
  82.                 string = [NSString stringWithFormat:@"%.2f  %.2f  %.2f", load0, load1, load2];
  83.                 if ((load0>=10.0) || (load1>=10.0) || (load2>=10.0)) string = [NSString stringWithFormat:@"%.1f  %.1f  %.1f", load0, load1, load2]; // for such a load, it is stupid to have two digits after the point, and it would not be well displayed, because too long. Actually, it would be better to study each value separately, but is it really useful ? no
  84.             [fontAttrs setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
  85.             [string drawAtPoint:NSMakePoint(4.0, 84.0) withAttributes:fontAttrs];
  86.             [fontAttrs setObject:[NSColor whiteColor] forKey:NSForegroundColorAttributeName];
  87.             [string drawAtPoint:NSMakePoint(2.0, 86.0) withAttributes:fontAttrs];
  88.             
  89.                         [fontAttrs release];
  90.     }
  91. /* gauge */ if (showGauge) {               
  92.                 fontAttrs = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  93.                 [NSFont systemFontOfSize:9.0], NSFontAttributeName,
  94.                 [NSColor whiteColor], NSForegroundColorAttributeName,
  95.                 nil];
  96.  
  97.                 if (LOAD_MAX > 9) delta_coeff = 2; // for leon and his busy G4
  98.                 else delta_coeff = 1;
  99.                  
  100.                 string = [NSString stringWithFormat:@"------------------------"];
  101.                 for (y=128./LOAD_MAX * delta_coeff;y<=128.*(LOAD_MAX-1)/LOAD_MAX;y+=128./LOAD_MAX * delta_coeff){
  102.                     [ string drawAtPoint:NSMakePoint( 10.0+(delta_coeff-1)*6, y - 6.0 ) withAttributes:fontAttrs];
  103.                     aString = [NSString stringWithFormat:@"%.0f", y * LOAD_MAX / 128. ];
  104.                 aSize = [aString sizeWithAttributes:fontAttrs];
  105.                     [aString drawAtPoint:NSMakePoint( 8.0+(delta_coeff-1)*6 - aSize.width, y - 6.0 ) withAttributes:fontAttrs];
  106.                     }
  107.                     
  108.                         [fontAttrs release];
  109. /* end gauge */}
  110.  
  111. }
  112.  
  113.  
  114. - (void)drawComplete
  115. // completely redraw graphImage, put graph and pageing rate into iconImage
  116. {    
  117.     VMData            vmdata;
  118.     int            x;
  119.     float            y, yy;        
  120.     float             transparency = [[preferences objectForKey:TRANSPARENCY_KEY] floatValue];
  121.     double             pgfactor;
  122.     double             lastload1 = 0.0, lastload2 = 0.0;
  123.         int             LOAD_MIN_PREF = [[preferences objectForKey:PAGING_SCALE_MAX_KEY] intValue];
  124.         double            my_max = LOAD_MIN_PREF; // for speed improving
  125.  
  126.         if (LOAD_MAX < LOAD_MIN_PREF){ // make sure the minimal value displayed is the one defined in the preferences
  127.             LOAD_MAX = LOAD_MIN_PREF;    // thus does nothing or increase       
  128.             }
  129.             
  130.         pgfactor = 1.0 / LOAD_MAX;
  131.  
  132.         [graphImage lockFocus];
  133.  
  134.     // erase graph image with background color
  135.     [[[preferences objectForKey:FREE_COLOR_KEY] colorWithAlphaComponent:transparency] set];
  136.     NSRectFill (NSMakeRect(0.0, 0.0, GRAPH_SIZE, GRAPH_SIZE));
  137.  
  138.     // draw  chronological graph into graph image
  139.     [memInfo startIterate];
  140.                       
  141.     for (x = 0; [memInfo getNext:&vmdata]; x++) {
  142.         
  143.                 if (vmdata.load0 > my_max){ // for speed improving
  144.                                                 x_max = x;
  145.                                                 my_max = vmdata.load0;
  146.                                             } 
  147.                 if (vmdata.load1 > my_max){ // for speed improving
  148.                                                 x_max = x;
  149.                                                 my_max = vmdata.load1;
  150.                                             }
  151.                 if (vmdata.load2 > my_max){ // for speed improving
  152.                                                 x_max = x;
  153.                                                 my_max = vmdata.load2;
  154.                                             }
  155.                 
  156.         y = vmdata.load0 * GRAPH_SIZE * pgfactor;
  157.         [[[preferences objectForKey:WIRED_COLOR_KEY] colorWithAlphaComponent:transparency] set];
  158.         [NSBezierPath strokeLineFromPoint:NSMakePoint(x, 0.0) toPoint:NSMakePoint(x, y)];
  159.         
  160.         if (x) {
  161.                         y = GRAPH_SIZE * vmdata.load1 * pgfactor;
  162.                         yy = GRAPH_SIZE * lastload1 * pgfactor;
  163.             [[preferences objectForKey:PAGEIN_COLOR_KEY] set];
  164.             [NSBezierPath strokeLineFromPoint:NSMakePoint(x - 1, yy) toPoint:NSMakePoint(x, y)];
  165.  
  166.                         y = GRAPH_SIZE * vmdata.load2 * pgfactor;
  167.             yy = GRAPH_SIZE * lastload2 * pgfactor;
  168.             [[preferences objectForKey:PAGEOUT_COLOR_KEY] set];
  169.             [NSBezierPath strokeLineFromPoint:NSMakePoint(x - 1, yy) toPoint:NSMakePoint(x, y)];
  170.         }
  171.         lastload1 = vmdata.load1;
  172.         lastload2 = vmdata.load2;
  173.     }
  174.         
  175.         // transfer graph image to icon image
  176.     [graphImage unlockFocus];
  177.     [iconImage lockFocus];    
  178.     [graphImage compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeCopy];
  179.     
  180.     // draw paging rate into the icon image
  181.     [self drawPageins:vmdata.load1 pageouts:vmdata.load2 load0:vmdata.load0];
  182.     
  183.     [iconImage unlockFocus];
  184. }
  185.  
  186.  
  187. - (void)drawDelta
  188. // update graphImage (based on previous graphImage), put graph and pageing rate into iconImage
  189. {    
  190.     VMData            vmdata, vmdata0;
  191.     float            y, yy;    
  192.     float             transparency = [[preferences objectForKey:TRANSPARENCY_KEY] floatValue];
  193.     double             pgfactor = 1.0 / LOAD_MAX;
  194.  
  195.         int             x;
  196.         int             VISIBLE_MAX = [[preferences objectForKey:PAGING_SCALE_MAX_KEY] intValue]; // reference for comparison
  197.         double            my_max = VISIBLE_MAX; // for speed improving
  198.         VMData            completevmdata;
  199.         int             dcflag = 0; // draw complete flag
  200.                 
  201.     [graphImage lockFocus];
  202.  
  203.     // offset the old graph image
  204.     [graphImage compositeToPoint:NSMakePoint(-1, 0) operation:NSCompositeCopy];
  205.     
  206.     [[[preferences objectForKey:FREE_COLOR_KEY] colorWithAlphaComponent:transparency] set];
  207.     NSRectFill (NSMakeRect(GRAPH_SIZE - 1, 0.0, GRAPH_SIZE, GRAPH_SIZE));
  208.     
  209.     [memInfo getLast:&vmdata0];
  210.     [memInfo getCurrent:&vmdata];
  211.     
  212.     // draw chronological graph into graph image
  213.     y = vmdata.load0 * GRAPH_SIZE * pgfactor;
  214.     [[[preferences objectForKey:WIRED_COLOR_KEY] colorWithAlphaComponent:transparency] set];
  215.     [NSBezierPath strokeLineFromPoint:NSMakePoint(GRAPH_SIZE - 1, 0.0) toPoint:NSMakePoint(GRAPH_SIZE - 1, y)];
  216.  
  217.         y = GRAPH_SIZE * vmdata.load1 * pgfactor;
  218.         yy = GRAPH_SIZE * vmdata0.load1 * pgfactor;
  219.     [[preferences objectForKey:PAGEIN_COLOR_KEY] set];
  220.     [NSBezierPath strokeLineFromPoint:NSMakePoint(GRAPH_SIZE - 2, yy) toPoint:NSMakePoint(GRAPH_SIZE - 1, y)];
  221.  
  222.         y = GRAPH_SIZE * vmdata.load2 * pgfactor;
  223.         yy = GRAPH_SIZE * vmdata0.load2 * pgfactor;
  224.  
  225.     [[preferences objectForKey:PAGEOUT_COLOR_KEY] set];
  226.     [NSBezierPath strokeLineFromPoint:NSMakePoint(GRAPH_SIZE - 2, yy) toPoint:NSMakePoint(GRAPH_SIZE - 1, y)];
  227.  
  228.     // transfer graph image to icon image
  229.     [graphImage unlockFocus];
  230.     [iconImage lockFocus];
  231.     [graphImage compositeToPoint:NSMakePoint(0, 0) operation:NSCompositeCopy];
  232.  
  233.     // draw load text into the icon image
  234.     [self drawPageins:vmdata.load1 pageouts:vmdata.load2 load0:vmdata.load0];
  235.  
  236.     [iconImage unlockFocus];
  237.         
  238. // now the tricky part (for me and my poor programming knowledge)        
  239.         if (vmdata.load0 > (double)LOAD_MAX){ // if new value higher as everything before, update complete window
  240.                 LOAD_MAX = ceil(vmdata.load0); // thus do nothing or increase
  241.                 dcflag = 1;//[self drawComplete];
  242.         }
  243.         else {
  244.                 x_max--; // for speed improving
  245.                 //printf("x_max : %d\n",x_max);
  246.                 if (x_max < 0){ // if the max is out of the window, look for a new max
  247.         // this should be the right place to look for the max value displayed in the window and to adapt the scaling to it
  248.             [memInfo startIterate]; // Very important, without it, it does not work !!!
  249.             for (x = 0; [memInfo getNext:&completevmdata]; x++) { //test 
  250.                 //printf("%d ",x);
  251.                     if (completevmdata.load0 > my_max){
  252.                                                                         x_max = x; // for speed improving
  253.                                                                         my_max = completevmdata.load0;
  254.                     }
  255.                     if (completevmdata.load1 > my_max){
  256.                                                                         x_max = x; // for speed improving
  257.                                                                         my_max = completevmdata.load1;
  258.                     }
  259.                     if (completevmdata.load2 > my_max){
  260.                                                                         x_max = x; // for speed improving
  261.                                                                         my_max = completevmdata.load2;
  262.                     }
  263.                 }
  264.                 VISIBLE_MAX = ceil(my_max);
  265.                 
  266.                 if (VISIBLE_MAX < LOAD_MAX){ // this should do nothing or decrease !
  267.                     LOAD_MAX = VISIBLE_MAX; // update LOAD_MAX before new display
  268.                     dcflag = 1;//[self drawComplete];
  269.                     }
  270.                 }
  271.         }
  272.         if (dcflag) [self drawComplete];
  273. }
  274.  
  275.  
  276. - (void)refreshIcon
  277. // get a new sample and refresh the dock icon
  278. {
  279.     [memInfo refresh];
  280.     [self drawDelta];
  281.     [NSApp setApplicationIconImage:iconImage];
  282.     
  283.     if ([[preferences objectForKey:SHOW_GRAPH_WINDOW_KEY] boolValue]) {
  284.         [window disableFlushWindow];
  285.         [view display];
  286.         [window enableFlushWindow];
  287.         [window flushWindow];
  288.     }
  289. }
  290.  
  291.  
  292. - (void)updateIcon
  293. // only refresh the dock icon (to show new preferences settings)
  294. {
  295.     [self drawComplete];
  296.     [NSApp setApplicationIconImage:iconImage];
  297.     
  298.     if ([[preferences objectForKey:SHOW_GRAPH_WINDOW_KEY] boolValue]) {
  299.         [window disableFlushWindow];
  300.         [view display];
  301.         [window enableFlushWindow];
  302.         [window flushWindow];
  303.     }
  304. }
  305.  
  306.  
  307. - (void)setTimer
  308. {
  309.     double newInterval = 0.1 * [[preferences objectForKey:UPDATE_FREQUENCY_KEY] floatValue];
  310.  
  311.     if (timer) {
  312.         if (fabs([timer timeInterval] - newInterval) < 0.001)
  313.             return;        /* frequency not changed */
  314.         [timer invalidate];
  315.         [timer release];
  316.     }
  317.     timer = [NSTimer scheduledTimerWithTimeInterval:newInterval
  318.         target:self selector:@selector(refreshIcon) userInfo:nil repeats:YES];
  319.     [timer retain];
  320. }
  321.  
  322.  
  323. - (void)showPreferences:(id)sender
  324. {
  325.         [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; // we go in foreground in case of using the dock menu
  326.     [preferences showPreferences:self];
  327. }
  328.  
  329.  
  330. - (BOOL)isLoginItem
  331. {
  332.     id    obj;
  333.     
  334.     NSString *memoryMonitorPath = [[NSBundle mainBundle] bundlePath];
  335.     NSDictionary *loginItemDict = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Library/Preferences/loginwindow.plist", NSHomeDirectory()]];
  336.     NSEnumerator *loginItemEnumerator = [[loginItemDict objectForKey:@"AutoLaunchedApplicationDictionary"] objectEnumerator];
  337.  
  338.     while ((obj = [loginItemEnumerator nextObject])) {
  339.         if ([[obj objectForKey:@"Path"] isEqualTo:memoryMonitorPath])
  340.             return (YES);
  341.     }
  342.     return (NO);
  343. }
  344.  
  345.  
  346. - (unsigned)systemVersion
  347. // returns the system version normally retrieved with Gestalt(gestaltSystemVersion, &systemVersion)
  348. {
  349.     const char    *p;
  350.     
  351.     unsigned version = 0;
  352.     
  353.     for (p = [[[NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]
  354.         objectForKey:@"ProductVersion"] cString]; *p; p++) {
  355.         if (*p != '.')
  356.             version = (version << 4) | (*p - '0');
  357.     }
  358.     if (version < 0x1000)    // for 10.0, 10.1
  359.         version <<= 4;
  360.     return (version);
  361. }
  362.  
  363.  
  364. - (void)applicationDidFinishLaunching:(NSNotification *)notification
  365. {
  366.     preferences = [[Preferences alloc] init];
  367.     memInfo = [[MemInfo alloc] initWithCapacity:GRAPH_SIZE];
  368. LOAD_MAX = [[preferences objectForKey:PAGING_SCALE_MAX_KEY] intValue]; // initial value
  369.     iconImage = [[NSImage allocWithZone:[self zone]] initWithSize:NSMakeSize(GRAPH_SIZE, GRAPH_SIZE)];
  370.     graphImage = [[NSImage allocWithZone:[self zone]] initWithSize:NSMakeSize(GRAPH_SIZE, GRAPH_SIZE)];
  371.     [self drawComplete];
  372.  
  373.     window = [[TranslucentWindow allocWithZone:[self zone]]
  374.         initWithContentRect:NSMakeRect(0.0, 0.0, GRAPH_SIZE, GRAPH_SIZE)
  375.         styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
  376.     [window setReleasedWhenClosed:NO];
  377.     [window setBackgroundColor:[NSColor clearColor]];
  378.     [window setFrameAutosaveName:@"LoadMonitorWindowLocation"];
  379.  
  380.     view = [[TranslucentView allocWithZone:[self zone]] initWithFrame:NSMakeRect(0.0, 0.0, GRAPH_SIZE, GRAPH_SIZE)];
  381.     [window setContentView:view];
  382.     [view setContentDrawer:self method:@selector(drawImageOnWindow)];
  383.     [view setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)];
  384.     [view setToolTip:@"Load Monitor"];
  385.     
  386.     [self showHideWindow];
  387.  
  388.     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showHideWindow) name:PREFERENCES_CHANGED object:nil];
  389.     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateIcon) name:PREFERENCES_CHANGED object:nil];
  390.     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setTimer) name:PREFERENCES_CHANGED object:nil];
  391.  
  392.     if ([self systemVersion] < 0x1010 && [self isLoginItem])
  393.         [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(setTimer) userInfo:nil repeats:NO];
  394.     else
  395.         [self setTimer];
  396. }
  397.  
  398.  
  399. - (void)applicationWillTerminate:(NSNotification *)aNotification 
  400. {
  401.     if (timer) {
  402.         [timer invalidate];
  403.         [timer release];
  404.         timer = nil;
  405.     }
  406.     [preferences savePreferences];
  407.     [NSApp setApplicationIconImage:[NSImage imageNamed:@"icn_load.icns"]];    
  408. }
  409.  
  410. /*
  411. - (void)showAboutBox:(id)sender
  412. {
  413.     if (! aboutBox) {
  414.         if ([NSBundle loadNibNamed:@"About" owner:self])
  415.             [aboutBox center];
  416.         else {
  417.             NSLog (@"Failed to load About.nib");
  418.             return;
  419.         }
  420.     }
  421.     [aboutBox makeKeyAndOrderFront:nil];
  422. }
  423. */
  424. - (IBAction)showAboutBox:(id)sender
  425. {
  426.     if ((GetCurrentKeyModifiers() & (optionKey | rightOptionKey)) != 0)
  427.     {
  428.         NSRunAlertPanel(@"You found it !",@"http://www.cocoadevcentral.com is great !\n\nMacOSiX le gaulois est plus fort que WinXPus.", @"OK",NULL,NULL);
  429.     }
  430.     else
  431.     {   [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; // we go in foreground in case of using the dock menu
  432.         [[AboutBox sharedInstance] showPanel:sender];
  433.     }
  434. }
  435.  
  436. @end
  437.